package services

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"miracle-recorder/internal/models"
)

type AIService struct {
	BaseURL string
	Client  *http.Client
}

func NewAIService(baseURL string) *AIService {
	return &AIService{
		BaseURL: baseURL,
		Client: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

func (s *AIService) SummarizeContent(req *models.AISummarizeRequest) (*string, error) {
	payload := map[string]interface{}{
		"content":   req.Content,
		"language":  req.Language,
		"keywords":  req.Keywords,
		"task":      "summarize",
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := s.Client.Post(s.BaseURL+"/summarize", "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to send request to AI service: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("AI service returned status: %d", resp.StatusCode)
	}

	var result struct {
		Summary string `json:"summary"`
		Error   string `json:"error"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("failed to decode AI response: %w", err)
	}

	if result.Error != "" {
		return nil, fmt.Errorf("AI service error: %s", result.Error)
	}

	return &result.Summary, nil
}

func (s *AIService) GenerateSolution(req *models.GenerateSolutionRequest) (*string, error) {
	payload := map[string]interface{}{
		"topic_id": req.TopicID,
		"content":  req.Content,
		"type":     req.Type,
		"keywords": req.Keywords,
		"task":     "generate_solution",
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := s.Client.Post(s.BaseURL+"/generate-solution", "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to send request to AI service: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("AI service returned status: %d", resp.StatusCode)
	}

	var result struct {
		Solution string `json:"solution"`
		Error    string `json:"error"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("failed to decode AI response: %w", err)
	}

	if result.Error != "" {
		return nil, fmt.Errorf("AI service error: %s", result.Error)
	}

	return &result.Solution, nil
}

func (s *AIService) AnalyzeCredibility(content string, mediaType string) (*float64, error) {
	payload := map[string]interface{}{
		"content":    content,
		"media_type": mediaType,
		"task":       "analyze_credibility",
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := s.Client.Post(s.BaseURL+"/analyze-credibility", "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to send request to AI service: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("AI service returned status: %d", resp.StatusCode)
	}

	var result struct {
		CredibilityScore float64 `json:"credibility_score"`
		Error           string  `json:"error"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("failed to decode AI response: %w", err)
	}

	if result.Error != "" {
		return nil, fmt.Errorf("AI service error: %s", result.Error)
	}

	return &result.CredibilityScore, nil
}

type UploadService struct {
	UploadPath string
}

func NewUploadService(uploadPath string) *UploadService {
	// 确保上传目录存在
	if err := os.MkdirAll(uploadPath, 0755); err != nil {
		panic(fmt.Sprintf("Failed to create upload directory: %v", err))
	}
	return &UploadService{UploadPath: uploadPath}
}

func (s *UploadService) UploadFile(file multipart.File, header *multipart.FileHeader, allowedTypes []string) (*string, error) {
	// 检查文件类型
	ext := strings.ToLower(filepath.Ext(header.Filename))
	if !s.isAllowedType(ext, allowedTypes) {
		return nil, fmt.Errorf("file type %s not allowed", ext)
	}

	// 生成唯一文件名
	filename := fmt.Sprintf("%d_%s%s", time.Now().Unix(), s.generateRandomString(8), ext)
	filepath := filepath.Join(s.UploadPath, filename)

	// 创建文件
	dst, err := os.Create(filepath)
	if err != nil {
		return nil, fmt.Errorf("failed to create file: %w", err)
	}
	defer dst.Close()

	// 复制文件内容
	if _, err := io.Copy(dst, file); err != nil {
		return nil, fmt.Errorf("failed to save file: %w", err)
	}

	// 返回文件URL
	fileURL := fmt.Sprintf("/uploads/%s", filename)
	return &fileURL, nil
}

func (s *UploadService) GetFilePath(filename string) string {
	return filepath.Join(s.UploadPath, filename)
}

func (s *UploadService) DeleteFile(filename string) error {
	filepath := s.GetFilePath(filename)
	return os.Remove(filepath)
}

func (s *UploadService) GetFileType(filename string) string {
	ext := strings.ToLower(filepath.Ext(filename))
	switch ext {
	case ".jpg", ".jpeg", ".png", ".gif":
		return "image"
	case ".mp4", ".mov", ".avi":
		return "video"
	case ".mp3", ".wav":
		return "audio"
	case ".pdf", ".doc", ".docx":
		return "document"
	default:
		return "other"
	}
}

func (s *UploadService) isAllowedType(ext string, allowedTypes []string) bool {
	for _, allowed := range allowedTypes {
		if strings.ToLower(allowed) == ext {
			return true
		}
	}
	return false
}

func (s *UploadService) generateRandomString(length int) string {
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
	
	b := make([]byte, length)
	for i := range b {
		b[i] = charset[seededRand.Intn(len(charset))]
	}
	return string(b)
}

type NotificationService struct {
	db    *sql.DB
	redis *redis.Client
}

func NewNotificationService(db *sql.DB, redis *redis.Client) *NotificationService {
	return &NotificationService{db: db, redis: redis}
}

func (s *NotificationService) CreateNotification(notification *models.Notification) error {
	query := `
		INSERT INTO notifications (user_id, type, title, message, data, is_read, created_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
		RETURNING id
	`

	err := s.db.QueryRow(query,
		notification.UserID,
		notification.Type,
		notification.Title,
		notification.Message,
		notification.Data,
		notification.IsRead,
		time.Now(),
	).Scan(&notification.ID)

	if err != nil {
		return fmt.Errorf("failed to create notification: %w", err)
	}

	return nil
}

func (s *NotificationService) GetUserNotifications(userID int, limit, offset int) ([]*models.Notification, error) {
	query := `
		SELECT id, user_id, type, title, message, data, is_read, created_at
		FROM notifications
		WHERE user_id = $1
		ORDER BY created_at DESC
		LIMIT $2 OFFSET $3
	`

	rows, err := s.db.Query(query, userID, limit, offset)
	if err != nil {
		return nil, fmt.Errorf("failed to get notifications: %w", err)
	}
	defer rows.Close()

	var notifications []*models.Notification
	for rows.Next() {
		notification := &models.Notification{}

		err := rows.Scan(
			&notification.ID,
			&notification.UserID,
			&notification.Type,
			&notification.Title,
			&notification.Message,
			&notification.Data,
			&notification.IsRead,
			&notification.CreatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan notification: %w", err)
		}

		notifications = append(notifications, notification)
	}

	return notifications, nil
}

func (s *NotificationService) MarkAsRead(notificationID int) error {
	query := `
		UPDATE notifications
		SET is_read = true
		WHERE id = $1
	`

	_, err := s.db.Exec(query, notificationID)
	if err != nil {
		return fmt.Errorf("failed to mark notification as read: %w", err)
	}

	return nil
}